package com.ultrapower.util.topology;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class LinkCallData {
	private final String source;
	private final short sourceServiceType;

	private final String target;
	private final short targetServiceType;

	private final Map<Long, TimeHistogram> targetHistogramTimeMap;
	private final TimeWindow timeWindow;

	public LinkCallData(LinkKey linkKey) {
		this(linkKey, null);
	}

	public LinkCallData(LinkKey linkKey, TimeWindow timeWindow) {
		if (linkKey == null) {
			throw new NullPointerException("linkKey must not be null");
		}
		this.source = linkKey.getFromApplication();
		this.sourceServiceType = linkKey.getFromServiceType();

		this.target = linkKey.getToApplication();
		this.targetServiceType = linkKey.getToServiceType();

		this.targetHistogramTimeMap = new HashMap<>();
		this.timeWindow = timeWindow;
	}

	public TimeWindow getTimeWindow() {
		return timeWindow;
	}

	public String getSource() {
		return source;
	}

	public short getSourceServiceType() {
		return sourceServiceType;
	}

	public String getTarget() {
		return target;
	}

	public short getTargetServiceType() {
		return targetServiceType;
	}

	public Collection<TimeHistogram> getTimeHistogram() {
		return targetHistogramTimeMap.values();
	}

	public void addCallData(long timestamp, short slot, long count) {
		TimeHistogram histogram = getTimeHistogram(timestamp);
		histogram.addCallCount(slot, count);
	}

	public void addCallData(Collection<TimeHistogram> timeHistogramList) {
		for (TimeHistogram timeHistogram : timeHistogramList) {
			TimeHistogram histogram = getTimeHistogram(timeHistogram.getTimeStamp());
			histogram.add(timeHistogram);
		}
	}

	public void addRawCallData(LinkCallData copyLinkCallData) {
		if (copyLinkCallData == null) {
			throw new NullPointerException("copyLinkCallData must not be null");
		}
		if (!this.source.equals(copyLinkCallData.source)) {
			throw new IllegalArgumentException("source not equals");
		}
		if (this.sourceServiceType != copyLinkCallData.sourceServiceType) {
			throw new IllegalArgumentException("sourceServiceType not equals");
		}
		if (!this.target.equals(copyLinkCallData.target)) {
			throw new IllegalArgumentException("target not equals");
		}
		if (this.targetServiceType != copyLinkCallData.targetServiceType) {
			throw new IllegalArgumentException("targetServiceType not equals");
		}

		for (Map.Entry<Long, TimeHistogram> copyEntry : copyLinkCallData.targetHistogramTimeMap.entrySet()) {
			final Long timeStamp = copyEntry.getKey();
			TimeHistogram histogram = getTimeHistogram(timeStamp);
			histogram.add(copyEntry.getValue());
		}
	}

	private TimeHistogram getTimeHistogram(Long timeStamp) {
		long key = timeWindow != null ? timeWindow.refineTimestamp(timeStamp) : timeStamp;
		TimeHistogram histogram = targetHistogramTimeMap.get(key);
		if (histogram == null) {
			histogram = new TimeHistogram(targetServiceType, key);
			targetHistogramTimeMap.put(key, histogram);
		}
		return histogram;
	}

	public long getTotalCount() {
		long totalCount = 0;
		for (TimeHistogram timeHistogram : targetHistogramTimeMap.values()) {
			totalCount += timeHistogram.getTotalCount();
		}
		return totalCount;
	}

	@Override
	public String toString() {
		return "LinkCallData{" + "source='" + source + '\'' + ", sourceServiceType=" + sourceServiceType + ", target='"
				+ target + '\'' + ", targetServiceType=" + targetServiceType + '}';
	}
}
